#pragma once

#include <map>
#include <set>

#include "position.hpp"

template <typename T, int X, int Y>
class sysmap
{
    int m_x_size = X;
    int m_y_size = Y;

    std::map<int, std::map<int, std::set<T *>>> m_objects;

public:
    /**
     * @brief 判断指定位置上是否存在物体
     *
     * @param p
     * @return true
     * @return false
     */
    bool has_object(const Position &p)
    {
        auto iter_x = m_objects.find(p.x);
        if (m_objects.end() == iter_x)
        {
            return false;
        }

        auto iter_y = iter_x->second.find(p.y);
        if (iter_y == iter_x->second.end())
        {
            return false;
        }

        if (iter_y->second.empty())
        {
            return false;
        }

        return true;
    }

    std::set<T *> *get_objects(const Position &p)
    {
        auto iter_x = m_objects.find(p.x);

        if (iter_x != m_objects.end())
        {
            auto iter_y = iter_x->second.find(p.y);
            if (iter_y != iter_x->second.end())
            {
                return &(iter_y->second);
            }
        }
        return nullptr;
    }

    void put_object(T *c, const Position &p)
    {
        auto iter_x = m_objects.find(p.x);

        if (m_objects.end() == iter_x)
        {
            std::set<T *> tmp_set;
            tmp_set.insert(c);

            std::map<int, std::set<T *>> tmp_map;

            tmp_map[p.y] = tmp_set;

            m_objects[p.x] = tmp_map;

            return;
        }

        auto iter_y = iter_x->second.find(p.y);
        if (iter_y == iter_x->second.end())
        {
            std::set<T *> tmp_set;
            tmp_set.insert(c);

            iter_x->second[p.y] = tmp_set;

            return;
        }

        iter_y->second.insert(c);
    }

    void remove(const Position &p, T *obj)
    {
        std::cout << "remove: " << p.x << ", " << p.y << std::endl;
        auto iter_x = m_objects.find(p.x);
        if (iter_x != m_objects.end())
        {
            auto iter_y = iter_x->second.find(p.y);
            if (iter_y != iter_x->second.end())
            {
                iter_y->second.erase(obj);
            }
        }
    }

    bool has_position(const Position &p)
    {
        if (p.x < 0 || p.y < 0)
            return false;

        if (p.x >= m_x_size || p.y >= m_y_size)
            return false;

        return true;
    }

    /**
     * @brief 随机获得一个空白位置
     *
     * @param pret 出参，用于返回空白位置的坐标
     * @return true 成功获取到位置
     * @return false 已经没有空白的位置
     */
    bool random_space(Position &pret)
    {
        int count = 0;

        Position p = random_position(m_x_size, m_y_size);

        while (this->has_object(p))
        {
            p = random_position(m_x_size, m_y_size);

            if (++count > m_x_size * m_y_size)
            {
                // TODO 低性能,应该从随机位置出发去寻找最近的一个空白点; 待实现迭代器
                return false;
            }
        }

        pret = p;
        return true;
    }

    int total()
    {
        int ret = 0;
        for (auto x : m_objects)
        {
            for (auto y : x.second)
            {
                ret += y.second.size();
            }
        }
        return ret;
    }

    void clear()
    {
        m_objects.clear();
    }
};